#pragma once
#include<iostream>
#include<string>
#include <sys/types.h>
#include <sys/socket.h>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cerrno>
#include<netinet/in.h>
#include <arpa/inet.h>
#include<functional>
namespace Server
{
    using namespace std;
    using func_t = function<void(int,string,uint16_t,string)>;
    static const string defaultIp = "0.0.0.0";
    class udpServer
    {
    public:
        udpServer(func_t func,const uint16_t& port,const string& ip = defaultIp):_port(port),_socketfd(-1),_ip(ip),_callback(func)
        {}
        void Init()
        {
            //1.创建socket
            //AF_INET决定了要用ipv4地址（32位的）与端口号（16位的）的组合（入网）
            //SOCK_DGRAM -- UDP类型，不保证数据接收的顺序，非可靠连接
            _socketfd = socket(AF_INET,SOCK_DGRAM,0);
            if(_socketfd == -1)
            {
                cerr<<errno<<"socket"<<strerror(errno)<<endl;
                exit(2);
            }
            cout<<"socket success "<<_socketfd<<endl;
            //2.传入端口号和ip
            struct sockaddr_in local;
            bzero(&local,sizeof local);//把结构体初始化
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);//如果要给别人发信息，需要把你自己的ip和端口发出去，本地端口号也要转成网络版本
            //local.sin_addr.s_addr = inet_addr(_ip.c_str());//string->uiun32_t->htonl()->init_addr
            local.sin_addr.s_addr = htonl(INADDR_ANY);//任意地址bind
            int n = bind(_socketfd,(sockaddr*)&local,sizeof(local));
            if(n == -1)
            {
                cerr<<"bind err"<<errno<<strerror(errno)<<endl;
                exit(2);
            }
        }
        void start()
        {
            //服务器本质就是死循环
            char buffer[1024];
            while(1)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                ssize_t n = recvfrom(_socketfd,buffer,sizeof(buffer),0,(struct sockaddr*)&peer,&len);
                if(n > 0)
                {
                    //谁发来的信息，信息是什么？
                    buffer[n] = 0;
                    string ClientIp = inet_ntoa(peer.sin_addr);//将网络传来的二进制ip地址转换为十进制ip.
                    uint16_t ClientPort = ntohs(peer.sin_port);
                    string message = buffer;
                    cout<<"["<<ClientIp<<"] "<<"["<<ClientPort<<"] :"<<message<<endl; 
                    _callback(_socketfd,ClientIp,ClientPort,message);
                }
            }
        }
        ~udpServer()
        {}
    private:
        uint16_t _port;//端口号
        string _ip;//网络服务器不建议指明ip地址
        int _socketfd;
        func_t _callback;//回调函数
    };
}